﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using ProceduralCity.Textures;
using ProceduralCity.Textures.Walls;
using ProceduralCity.Textures.Windows;
using ProceduralCity.Utility;

namespace ProceduralCity.Models.Buildings
{
    class BlockyBuilding : BuildingBase
    {
        List<RectangularBuilding> buildings = new List<RectangularBuilding>();

        // TODO: This function should take a chunkSize parameter.
        // Idea: Generate a single large texture that is (width + depth, height) size. Use that to map textures to walls continuously. (Texture repeats, mirrored, for other side?).
        // TODO: Add a parameter that is a texture generator so that custom textures can be generated on the fly.
        public static BlockyBuilding RandomGenerate(Vector3 position, Vector3 lotSize, int numSubBuildings, Vector3 chunkSize)
        {
            // TODO: Require each building to protrude out of the others.
            Vector3 zFightingFudge = new Vector3(0.2f);
            BlockyBuilding building = new BlockyBuilding();
            for (int buildingIndex = 0; buildingIndex < numSubBuildings; ++buildingIndex)
            {
                RectangularBuilding subBuilding = RectangularBuilding.RandomGenerate(lotSize, chunkSize);
                subBuilding.Position = position + buildingIndex * zFightingFudge; // TODO: This should really be applied to the object's origin.

                building.AddSubBuilding(subBuilding);
            }

            // TODO: Consider making sure all casts to int round instead of truncate (application-wide).
            Vector3 buildingSizeInChunks = building.Size / chunkSize;
            SimpleWallTexture wallTexture = new SimpleWallTexture();
            wallTexture.Initialize((int)chunkSize.X, (int)chunkSize.Y, new SimpleWindowTexture(SimpleWindowTexture.WindowType.Random));
            wallTexture.Generate(
                (int)(2 * buildingSizeInChunks.X + 2 * buildingSizeInChunks.Z),
                (int)buildingSizeInChunks.Y);
            Texture2D topTexture = SolidTexture.Generate(Game.graphics.GraphicsDevice, 1, 1, Color.Black);

            foreach (RectangularBuilding b in building.buildings)
            {
                b.SetTextures(wallTexture.Texture, topTexture); // TODO: Consider not passing a texture to each sub-building. (configure effect.texture once in this class).
            }

            building.wallTexture = wallTexture.Texture;
            building.SetWallTextureCoordinates();
            return building;
        }

        public BlockyBuilding()
        { }

        public void AddSubBuilding(RectangularBuilding subBuilding)
        {
            buildings.Add(subBuilding);
            BoxBounds = new BoundingBox(
                Vector3.Min(BoxBounds.Min, subBuilding.BoxBounds.Min),
                Vector3.Max(BoxBounds.Max, subBuilding.BoxBounds.Max)
            );
        }

        protected override void DrawInternal(GraphicsDevice device, BasicEffect buildingEffect)
        {
            foreach (var subBuilding in buildings)
                subBuilding.Draw(device, buildingEffect);
        }

        public void SetWallTextureCoordinates()
        {
            float structurePerimeter = 2 * Size.X + 2 * Size.Z;
            float structureHeight = Size.Y;

            foreach (RectangularBuilding building in buildings)
            {
                Vector3 offset = building.BoxBounds.Min - BoxBounds.Min;
                building.SetWallTextureCoordinates(
                    offset.X / structurePerimeter,
                    building.Size.X / structurePerimeter,
                    offset.Z / structurePerimeter,
                    building.Size.Z / structurePerimeter,
                    (Size.Y - building.Size.Y) / structureHeight,
                    building.Size.Y / structureHeight
                );
            }
        }
    }
}
